package xj.graph2d.template;

import static javax.swing.SwingConstants.LEFT;
import static javax.swing.SwingConstants.VERTICAL;

import java.awt.Color;
import java.awt.Font;
import java.util.Map;

import javax.swing.Icon;

import xj.graph2d.Arrow;
import xj.graph2d.ArrowAttr;
import xj.graph2d.DrawAttr;
import xj.graph2d.DrawShape;
import xj.graph2d.DrawShapeConstants;
import xj.graph2d.FontAttrEx;
import xj.graph2d.GraphEdgeBase;
import xj.graph2d.GraphNodeBase;
import xj.graph2d.Group;
import xj.graph2d.Label;
import xj.graph2d.LineShape;
import xj.graph2d.OpenShape;
import xj.graph2d.RectangleShape;
import xj.graph2d.TextShape;
import xj.graph2d.shapes.BoxLabel;
import xj.graph2d.shapes.GraphEdgeShape;
import xj.graph2d.shapes.IconShape;
import xj.graph2d.shapes.RectangularShape;
import xj.graph2d.shapes.ShapeConstants;
import xj.graph2d.shapes.block.BlockShape;
import xj.graph2d.shapes.block.SimpleStatementShape;
import xj.graph2d.template.uml.UMLAssociationModelListener;
import xj.graph2d.template.uml.UMLDependencyModelListener;
import xj.graph2d.template.uml.UMLGeneralizationModelListener;
import xj.graph2d.template.uml.UMLNotesModelListener;
import xj.model.uml.Navigability;
import xj.model.uml.Note;
import xj.model.uml.UMLAssociation;
import xj.model.uml.UMLAssociationEnd;

import static xj.graph2d.template.VisualClassTemplate.NODE_COLOR;
import static xj.graph2d.template.VisualClassTemplate.NODE_FONT;
import static xj.graph2d.template.VisualClassTemplate.TRANSPARENT_COLOR;

public abstract class UMLTemplate 
  extends Template {

  public String[] getShapeToolNames() { 
    return null;
  }

  // edge type 

  public static final int GENERALIZATION_EDGE = 0x0001;
  public static final int REALIZATION_EDGE    = 0x0002;
  public static final int MIXIN_EDGE          = 0x0004;

  public static final int ASSOCIATION_EDGE    = 0x0010;
  public static final int DELEGATION_EDGE     = 0x0010;

  public static final int DEPENDENCY_EDGE     = 0x0080;

  public static final int TRANSITION_EDGE     = 0x0100;

  public static final int FLOW_EDGE           = 0x0200;

  // template style 

  public static final String CLASSIC_STYLE = ".classic";
  public static final String MODERN_STYLE  = ".modern";

  public static String toModernTemplateName(String temp) { 
    if (temp != null && 
	!temp.endsWith(MODERN_STYLE)) { 
      return temp + MODERN_STYLE;
    }
    return temp; 
  }

  public static String toClassicTemplateName(String temp) { 
    if (temp != null && 
	temp.endsWith(MODERN_STYLE)) { 
      return temp.substring(0, temp.length() - MODERN_STYLE.length());
    }
    return temp; 
  }

  protected UMLTemplate() {
  }

  public DrawShape setLineAttr(DrawShape shape, int lineStyle,
			       ArrowAttr.ArrowType headArrow, int headSize,
			       ArrowAttr.ArrowType tailArrow, int tailSize) {
    if (shape != null) {
      DrawAttr attr = new DrawAttr();
      shape.setDrawAttr(attr);
      attr.setLineStyle(lineStyle);
      attr.setPenSize(defaultEdgeWidth);
      if (shape instanceof OpenShape) {
	OpenShape oshape = (OpenShape) shape;
	setArrows(oshape, headArrow, headSize, tailArrow, tailSize);
      }
    }
    return shape;
  }

  public OpenShape setHeadArrow(OpenShape shape, 
				ArrowAttr.ArrowType headArrow,
				int headSize) {
    if (shape != null) {
      ArrowAttr headArrowAttr = null;
      if (headArrow != null && 
	  headArrow != Arrow.ArrowType.NoArrow) {
	headArrowAttr = new ArrowAttr();
	headArrowAttr.setType(headArrow);
	headArrowAttr.setSize(headSize);
      }
      shape.setHeadArrow(headArrowAttr);
    }
    return shape;
  }

  public OpenShape setTailArrow(OpenShape shape, 
				ArrowAttr.ArrowType tailArrow,
				int tailSize) {
    if (shape != null) {
      ArrowAttr tailArrowAttr = null;
      if (tailArrow != null && 
	  tailArrow != Arrow.ArrowType.NoArrow) {
	tailArrowAttr = new ArrowAttr();
	tailArrowAttr.setType(tailArrow);
	tailArrowAttr.setSize(tailSize);
      }
      shape.setTailArrow(tailArrowAttr);
    }
    return shape;
  }

  public OpenShape setArrows(OpenShape shape, 
			     ArrowAttr.ArrowType headArrow, int headSize, 
			     ArrowAttr.ArrowType tailArrow, int tailSize) {
    if (shape != null) {
      ArrowAttr headArrowAttr = null;
      ArrowAttr tailArrowAttr = null;
      if (headArrow != null && 
	  headArrow != Arrow.ArrowType.NoArrow) {
	headArrowAttr = new ArrowAttr();
	headArrowAttr.setType(headArrow);
	headArrowAttr.setSize(headSize);
      }
      if (tailArrow != null && 
	  tailArrow != Arrow.ArrowType.NoArrow) {
	tailArrowAttr = new ArrowAttr();
	tailArrowAttr.setType(tailArrow);
	tailArrowAttr.setSize(tailSize);
      }
      shape.addArrows(headArrowAttr, tailArrowAttr);
    }
    return shape;
  }

  public DrawShape setLineWidth(DrawShape shape, int w) {
    if (shape != null) {
      DrawAttr attr = shape.getDrawAttr();
      if (attr == null) {
	attr = new DrawAttr();
	shape.setDrawAttr(attr);
      }
      attr.setPenSize(w);
    }
    return shape;
  }

  static public TextShape setTextAttr(TextShape text, String name, int style, int size) {
    return setTextAttr(text, name, style, size, false);
  }

  static public TextShape setTextAttr(TextShape text, String name, int style,
				      int size, boolean underlined) {
    if (text != null) {
      DrawAttr attr = text.getDrawAttr();
      if (attr == null) {
	attr = new DrawAttr();
	text.setDrawAttr(attr);
      }
      attr.setFont(name, style, size);
      attr.setUnderlined(underlined);
    }
    return text;
  }

  public TextShape setTextAttr(TextShape text, String key) {
    if (text != null && 
	key != null && 
	styleOptions != null) {
      FontAttrEx font = getFontAttr(key);
      if (font != null) {
	return setTextAttr(text, font.fontName, font.fontStyle, font.fontSize,
			   font.underlined);
      }
    }
    return text;
  }

  public FontAttrEx getFontAttr(String key) {
    if (key != null && 
	styleOptions != null) {
      Object val = styleOptions.get(key);
      if (val instanceof String) {
	String fstring = (String) val;
	//System.out.println("UMLTemplate.getFontAttr() " + key + " " + fstring);
	String fontName = null;
	int fontStyle = Font.PLAIN;
	int fontSize = 10;
	boolean underlined = false;
	int i = fstring.indexOf(',');
	String skey;
	if (i > 0) {
	  fontName = fstring.substring(0, i);
	  fstring = fstring.substring(i + 1);
	}
	i = fstring.indexOf(',');
	if (i >= 0) {
	  skey = fstring.substring(0, i);
	  fstring = fstring.substring(i + 1).trim();
	  if (skey != null && skey.length() > 0) {
	    if (skey.indexOf('b') >= 0 || skey.indexOf('B') >= 0) {
	      fontStyle |= Font.BOLD;
	    }
	    if (skey.indexOf('i') >= 0 || skey.indexOf('I') >= 0) {
	      fontStyle |= Font.ITALIC;
	    }
	    if (skey.indexOf('u') >= 0 || skey.indexOf('U') >= 0) {
	      underlined = true;
	    }
	  }

	  try {
	    fontSize = Integer.parseInt(fstring);
	  } catch (NumberFormatException e) {
	    //e.printStackTrace();
	    fontSize = 10;
	  }
	}
	//System.out.println("UMLTemplate.getFontAttr() " + fontName + 
	//" " + fontStyle + " " + fontSize);
	return new FontAttrEx(fontName, fontStyle, fontSize, underlined);
      }
    }
    return null;
  }

  public TextShape makeTitleText(String prompt) {
    return makeTitleText(prompt, null, null, false, null, null);
  }

  public TextShape makeTitleText(String prompt,
				 String fontKey, String colorKey) {
    return makeTitleText(prompt, null, null, false, fontKey, colorKey);
  }

  public TextShape makeTitleText(String prompt, boolean multiline,
				 String fontKey, String colorKey) {
    return makeTitleText(prompt, null, null, multiline, fontKey, colorKey);
  }

  public TextShape makeTitleText(String prompt, 
				 String prefix, String suffix, 
				 String fontKey, String colorKey) {
    return makeTitleText(prompt, prefix, suffix, false, fontKey, colorKey);
  }

  public TextShape makeTitleText(String prompt, 
				 String prefix, String suffix, 
				 boolean multiline,
				 String fontKey, String colorKey) {
    TextShape text = new TextShape(null, prefix, suffix);
    text.setPrompt((prompt != null) ? prompt : "text");
    text.setRole(DrawShapeConstants.ROLE_LABEL);
    text.setAllowMultiLine(multiline);
    text.setDetachable(false);
    text.setScalable(false);
    text.setSticky(true);
    text.showCursor(true);
    if (colorKey != null) {
      setPenColor(text, colorKey);
    }
    if (fontKey != null) {
      setTextAttr(text, fontKey);
    } else {
      setTextAttr(text, "SansSerif", Font.BOLD, 12);
    }
    return text;
  }

  public BoxLabel makeTitleLabel(String prompt, Map iconMap) {
    return makeTitleLabel(prompt, iconMap, null, null);
  }

  public BoxLabel makeTitleLabel(String prompt, Map iconMap, String fontKey,
				 String colorKey) {
    return makeTitleLabel(prompt, iconMap, "classIcon", fontKey, colorKey);
  }

  public BoxLabel makeTitleLabel(String prompt, Map iconMap, String iconKey,
				 String fontKey, String colorKey) {
    TextShape text = makeTitleText(prompt, fontKey, colorKey);
    Icon icon = (Icon) iconMap.get(iconKey);
    BoxLabel label = new BoxLabel(new IconShape(icon, iconKey), text);
    label.setRole(DrawShapeConstants.ROLE_LABEL);
    label.setDetachable(false);
    label.setSelectable(false);
    label.setScalable(false);
    return label;
  }

  public TextShape makeContentText(String prompt) {
    return makeContentText(null, prompt, false);
  }

  public TextShape makeContentText(String s, String prompt) {
    return makeContentText(s, prompt, false);
  }

  public TextShape makeContentText(String s, String prompt, boolean multiline) {
    return makeContentText(s, prompt, multiline, null, null);
  }

  public TextShape makeContentText(String s, String prompt, boolean multiline,
				   String fontKey, String colorKey) {
    return makeContentText(s, prompt, null, null, multiline, fontKey, colorKey);
  }

  public TextShape makeContentText(String s, String prompt, 
				   String prefix, String suffix, 
				   boolean multiline, 
				   String fontKey, String colorKey) {
    TextShape text = new TextShape(s, prefix, suffix);
    text.setPrompt((prompt != null) ? prompt : "text");
    text.setAllowMultiLine(multiline);
    text.setDetachable(false);
    text.setScalable(false);
    text.showCursor(true);
    if (colorKey != null) {
      setPenColor(text, colorKey);
    }
    if (fontKey != null) {
      setTextAttr(text, fontKey);
    } else {
      setTextAttr(text, "SansSerif", Font.PLAIN, 10);
    }

    // System.out.println("UMLTemplate.makeContentText() isDetachable=" +
    // text.isDetachable());
    return text;
  }

  public BoxLabel makeTextGroup(String prompt, boolean multiline) {
    return makeTextGroup(prompt, multiline, null, null);
  }

  public BoxLabel makeTextGroup(String prompt, boolean multiline,
				String fontKey, String colorKey) {
    BoxLabel box = new BoxLabel(VERTICAL, LEFT);
    box.setPadding(0, 0);
    TextShape text = makeContentText(null, prompt, multiline, fontKey, colorKey);
    text.setDisplayName("");
    box.addShape(text);
    box.setMovable(false);
    box.setSelectable(false);
    return box;
  }

  public Label makeContentLabel(String prompt, Map iconMap, String iconKey) {
    return makeContentLabel(null, prompt, iconMap, iconKey);
  }

  public Label makeContentLabel(String s, String prompt, Map iconMap,
				String iconKey) {
    return makeContentLabel(s, prompt, iconMap, iconKey, null, null);
  }

  public Label makeContentLabel(String s, String prompt, Map iconMap,
				String iconKey, String fontKey, String colorKey) {
    TextShape text = makeContentText(s, prompt, 
				     true, // multiline 
				     fontKey, colorKey);
    Label label;
    if (iconKey != null && iconMap != null) {
      Icon icon = (Icon) iconMap.get(iconKey);
      BoxLabel blabel = new BoxLabel(new IconShape(icon), text);
      blabel.setPadding(0, 0);
      blabel.setSelectable(false); 
      label = blabel;
    } else {
      // label = new BoxLabel(null, text);
      label = text;
    }
    label.setDetachable(false);
    label.setScalable(false);
    return label;
  }

  public BoxLabel makeContentGroup(String prompt, Map iconMap, String iconKey) {
    return makeContentGroup(prompt, iconMap, iconKey, null, null);
  }

  public BoxLabel makeContentGroup(String prompt, Map iconMap, String iconKey,
				   String fontKey, String colorKey) {
    BoxLabel box = new BoxLabel(VERTICAL, LEFT);
    box.setPadding(0, 0);
    Label label = makeContentLabel(null, prompt, iconMap, iconKey, fontKey, colorKey);
    box.addShape(label);
    box.setMovable(false);
    box.setSelectable(false);
    return box;
  }

  public BlockShape makeBlockShape(int blockType, int elementType, 
				  String fgColorKey, String bgColorKey,
				  String display, String prompt) { 
    BlockShape block = new BlockShape();
    block.setBlockType(blockType);
    setNodeAttr(block);
    setNodeColor(block, fgColorKey, null); // TRANSPARENT_COLOR);
    block.setFilled(false);

    SimpleStatementShape stmt = makeElementShape(elementType, display, prompt,
						 fgColorKey, bgColorKey);
    block.addShape(stmt);
    block.setShowHeader(false);
    block.setMovable(false);
    block.setSelectable(false);
    block.showBorder(false);
    block.setShadow(false);
    block.setFitted(true);
    block.setTopMargin(0);
    block.setBottomMargin(0);
    block.doLayout();
    return block;
  }

  public SimpleStatementShape makeElementShape(int type, 
					       String display, String prompt,
					       String fgColorKey, String bgColorKey) { 
    SimpleStatementShape stmt = new SimpleStatementShape(0, 0, 120, 16);
    stmt.setDisplayName(display);
    stmt.setStatementType(type);
    setNodeAttr(stmt);
    setNodeColor(stmt, fgColorKey, bgColorKey);
    TextShape text = null;
    text = makeTitleText(prompt, null, null, NODE_FONT, NODE_COLOR);
    text.setDisplayName(display);
    text.setMarkString(true);
    setFillColor(text, Color.white);
    stmt.setLabel(DrawShapeConstants.ROLE_NODE_LABEL, text);
    stmt.setLabelPosition(GraphNodeBase.LABEL_POSITION_LEFT_ADJUST);
    stmt.layoutComponents();
    return stmt; 
  }

  public DrawShape makeGenericTemplateShape(float w, float h) {
    RectangleShape tshape = new RectangleShape(0, 0, w, h);
    setNodeBgColor(tshape, Color.white);
    DrawAttr attr = tshape.getDrawAttr();
    if (attr == null) {
      attr = new DrawAttr();
      tshape.setDrawAttr(attr);
    }
    attr.setLineStyle(DrawAttr.DASHED_LINE);

    TextShape text = makeContentText(null, "Generics", true, GENERICS_FONT, GENERICS_COLOR);
    tshape.setLabel(DrawShapeConstants.ROLE_NODE_LABEL, text);
    tshape.setDisplayName("Generics");
    text.setDisplayName("Type name");
    text.setDetachable(false);
    text.setMovable(false);

    tshape.setDetachable(false);
    tshape.setScalable(false);
    tshape.setAcceptSubshape(false);
    tshape.setSymetricResize(false);
    tshape.setAllowRotation(false);
    return tshape;
  }

  public DrawShape makeDocumentHeader(String h, String fontKey, String colorKey) { 
    TextShape text = new TextShape(h); 
    text.setPrompt("header");
    text.setRole(DrawShapeConstants.ROLE_DOCUMENT_HEADER);
    text.setAllowMultiLine(false);
    text.setDetachable(false);
    text.setScalable(false);
    text.setSticky(true);
    text.setEditable(false);
    text.setMovable(false);
    text.showCursor(false);
    if (colorKey != null) {
      setPenColor(text, colorKey);
    }
    if (fontKey != null) {
      setTextAttr(text, fontKey);
    } else {
      setTextAttr(text, "SansSerif", Font.BOLD, 12);
    }
    return text;
  }

  protected void addNotesTemplate(String tempName) {
    addNotesTemplate(tempName, false, null);
  }

  protected void addNotesTemplate(String tempName, boolean link) {
    addNotesTemplate(tempName, link, null);
  }

  protected void addNotesTemplate(String tempName, boolean link, String linkTempName) {
    int iconWidth = 36, iconHeight = 30;
    DrawShape iconShape, shape;
    DrawShape inshape = new RectangularShape(ShapeConstants.NOTES_SHAPE,
					     ShapeConstants.NORTH, 0, 0, 100, 70);
    setNodeAttr(inshape);
    // setNodeBgColor(inshape, NOTES_BG);
    setNodeColor(inshape, NOTES_FG, NOTES_BG);

    RectangularShape nshape = new RectangularShape(ShapeConstants.NOTES_SHAPE, 
						   ShapeConstants.NORTH, 
						   0, 0, 100, 70);
    setNodeAttr(nshape);
    setNodeColor(nshape, NOTES_FG, NOTES_BG);
    BoxLabel tbox = makeTextGroup("notes", true, NOTES_FONT, NOTES_COLOR);
    // allow multiple lines
    tbox.setDisplayName("Text");
    tbox.setDisplayTextMode(BoxLabel.DSIPLAY_TEXT_FIRST_LINE);
    nshape.setLabel(DrawShapeConstants.ROLE_NODE_LABEL, tbox);
    nshape.setAcceptSubshape(false);
    nshape.setScaleMode(DrawShapeConstants.SCALE_EXCLUDE_SUBSHAPE);
    nshape.doLayout();

    nshape.setModel(new Note());
    nshape.setModelListener(new UMLNotesModelListener());

    if (link) {
      LineShape line = new LineShape(50, 70, 50, 100);
      setLineAttr(line, DrawAttr.DOTTED_LINE, ArrowAttr.ArrowType.HollowDot, 5, null, 0);
      setPenColor(line, NOTES_FG);
      Group iconGroup = new Group();
      iconGroup.addShape(inshape);
      iconGroup.addShape(line);
      iconGroup.fitComponents();

      nshape.initComponent();
      line = new LineShape(50, 35, 50, 100);
      setLineAttr(line, DrawAttr.DOTTED_LINE, ArrowAttr.ArrowType.HollowDot, 5, null, 0);
      setPenColor(line, NOTES_FG);
      line.initComponent();
      UMLAssociation model = new UMLAssociation(UMLAssociation.AssociationType.Notes_Link);
      model.setNavigabilityToRight(null);
      model.setNavigabilityToLeft(null);
      line.setModel(model);
      line.setModelListener(new UMLAssociationModelListener(this));
      line.setTemplateName(linkTempName);
      Group group = new Group(true);
      group.addShape(nshape);
      group.addShape(line);

      shape = group;
      iconShape = iconGroup;
      iconWidth = 36;
      iconHeight = 30;
    } else {
      shape = nshape;
      iconShape = inshape;
      iconWidth = 36;
      iconHeight = 24;
    }

    add(new TemplateToolButton(tempName, shape, iconShape, iconWidth, iconHeight, false, true));
  }

  protected void addNotesLinkTemplate(String tempName, GraphEdgeBase shape) {
    if (shape == null) {
      shape = new LineShape(0, 20, 50, 20);
    }
    setLineAttr(shape, DrawAttr.DOTTED_LINE, ArrowAttr.ArrowType.HollowDot, 5, null, 0);
    setPenColor(shape, NOTES_FG);

    UMLAssociation model = new UMLAssociation(UMLAssociation.AssociationType.Notes_Link);
    model.setNavigabilityToRight(null);
    model.setNavigabilityToLeft(null);
    shape.setModel(model);
    shape.setModelListener(new UMLAssociationModelListener(this));
    add(new TemplateToolButton(tempName, shape, 36, 30, false, true));
  }

  protected void addDependencyTemplate(String tempName) {
    addDependencyTemplate(tempName, null, null);
  }

  protected void addDependencyTemplate(String tempName, String colorkey) {
    addDependencyTemplate(tempName, null, colorkey);
  }

  protected void addDependencyTemplate(String tempName, GraphEdgeBase shape) {
    addDependencyTemplate(tempName, shape, null);
  }

  protected void addDependencyTemplate(String tempName, GraphEdgeBase shape,
				       String colorkey) {
    addDependencyTemplate(tempName, shape, null,
			  UMLAssociation.AssociationType.Dependency, colorkey);
  }

  protected void addDependencyTemplate(String tempName, GraphEdgeBase shape,
				       UMLAssociation.AssociationType dtype, String colorkey) {

    addDependencyTemplate(tempName, shape, null, dtype, colorkey);			  
  }

  protected void addDependencyTemplate(String tempName, 
				       GraphEdgeBase shape, DrawShape iconShape,
				       UMLAssociation.AssociationType dtype, String colorkey) {
    addDependencyTemplate(tempName, shape, iconShape, dtype, 
			  false, colorkey, TemplateToolButton.TOOL_PANEL_BUTTON);
  }

  protected void addDependencyTemplate(String tempName, 
				       GraphEdgeBase shape, DrawShape iconShape,
				       UMLAssociation.AssociationType dtype, 
				       boolean reverseEnds, 
				       String colorkey, 
				       int buttonType) {
    if (shape == null) {
      shape = new GraphEdgeShape(0, 20, 50, 20);
      iconShape = new LineShape(0, 20, 50, 20);
    }
    setLineAttr(shape, DrawAttr.DOTTED_LINE, ArrowAttr.ArrowType.LineArrow, 12,	null, 0);
    if (colorkey != null) {
      setPenColor(shape, colorkey);
    }
    shape.setEdgeType(DEPENDENCY_EDGE);

    UMLAssociation model = new UMLAssociation(dtype);
    model.setNavigabilityToRight(null);
    model.setNavigabilityToLeft(null);
    shape.setModel(model);
    // shape.setModelListener(new UMLAssociationModelListener(this));
    shape.setModelListener(new UMLDependencyModelListener(this));

    if (iconShape != null) { 
      setLineAttr(iconShape, DrawAttr.DOTTED_LINE, ArrowAttr.ArrowType.LineArrow, 12, null, 0);
      if (colorkey != null) {
	setPenColor(iconShape, colorkey);
      }
      add(new TemplateToolButton(tempName, shape, iconShape, 36, 24, false, true,
				 TemplateToolButton.DEFAULT_TOOL, reverseEnds, buttonType));
    } else { 
      add(new TemplateToolButton(tempName, shape, 36, 24, false, true,
				 TemplateToolButton.DEFAULT_TOOL, reverseEnds, buttonType));
    }
  }

  protected void addDependencyTemplate(String tempName, 
				       String protoName,
				       DrawShape iconShape,
				       int iconWidth, int iconHeight, 
				       boolean reverseEnds, 
				       String colorkey, 
				       int buttonType) {
    addDependencyTemplate(tempName, protoName, iconShape, iconWidth, iconHeight, 
			  UMLAssociation.AssociationType.Dependency,
			  reverseEnds, colorkey, buttonType);

  }

  protected void addDependencyTemplate(String tempName, 
				       String protoName,
				       DrawShape iconShape,
				       int iconWidth, int iconHeight, 
				       UMLAssociation.AssociationType dtype, 
				       boolean reverseEnds, 
				       String colorkey, 
				       int buttonType) {
    if (iconShape != null) { 
      setLineAttr(iconShape, DrawAttr.DOTTED_LINE, ArrowAttr.ArrowType.LineArrow, 12,	null, 0);
      if (colorkey != null) {
	setPenColor(iconShape, colorkey);
      }
      if (iconShape instanceof GraphEdgeBase) { 
	GraphEdgeBase edge = (GraphEdgeBase) iconShape;
	edge.setEdgeType(DEPENDENCY_EDGE);
      }
      add(new TemplateToolButton(tempName, protoName, iconShape, iconWidth, iconHeight, false, true,
				 TemplateToolButton.DEFAULT_TOOL, reverseEnds, buttonType));
    }
  }

  protected void addDependencyShapeTemplate(String name, 
					    GraphEdgeBase edge, 
					    String colorkey,
					    int iconWidth, int iconHeight) { 
    if (name != null && 
	edge != null) { 
      setLineAttr(edge, DrawAttr.DOTTED_LINE, ArrowAttr.ArrowType.LineArrow, 12, null, 0);
      if (colorkey != null) {
	setPenColor(edge, colorkey);
      }
      addEdgeShapeTemplate(name, edge, iconWidth, iconHeight);
    }
  }

  protected void addLinkTemplate(String tempName, GraphEdgeBase shape) {
    if (shape == null) {
      shape = new LineShape(0, 20, 50, 20);
    }
    setLineAttr(shape, DrawAttr.DOTTED_LINE, null, 0, null, 0);
    UMLAssociation model = new UMLAssociation(UMLAssociation.AssociationType.Link);
    model.setNavigabilityToRight(null);
    model.setNavigabilityToLeft(null);
    shape.setModel(model);
    shape.setModelListener(new UMLAssociationModelListener(this));
    add(new TemplateToolButton(tempName, shape, 36, 30, false, true));
  }

  protected void addGeneralizationTemplate(String tempName,
					   GraphEdgeBase shape,  
					   int iconWidth, int iconHeight, 
					   boolean realization, String colorkey) {
    addGeneralizationTemplate(tempName, shape, null, 
			      iconWidth, iconHeight, 
			      realization ? REALIZATION_EDGE : GENERALIZATION_EDGE, 
			      false, colorkey, TemplateToolButton.TOOL_PANEL_BUTTON);
  }

  protected void addGeneralizationTemplate(String tempName,
					   GraphEdgeBase shape, DrawShape iconShape,
					   int iconWidth, int iconHeight, 
					   boolean realization, 
					   String colorkey) {
    addGeneralizationTemplate(tempName, shape, iconShape, 
			      iconWidth, iconHeight, 
			      realization ? REALIZATION_EDGE : GENERALIZATION_EDGE, 
			      false, colorkey, TemplateToolButton.TOOL_PANEL_BUTTON);
  }

  protected void addGeneralizationTemplate(String tempName,
					   GraphEdgeBase shape, DrawShape iconShape,
					   int iconWidth, int iconHeight, 
					   boolean realization, 
					   String colorkey, 
					   int buttonType) {
    addGeneralizationTemplate(tempName, shape, iconShape, 
			      iconWidth, iconHeight, 
			      realization ? REALIZATION_EDGE : GENERALIZATION_EDGE, 
			      false, colorkey, buttonType);
  }

  protected void addGeneralizationTemplate(String tempName,
					   GraphEdgeBase shape, DrawShape iconShape,
					   int iconWidth, int iconHeight, 
					   boolean realization, 
					   boolean reverseEnds, 
					   String colorkey, 
					   int buttonType) {
    addGeneralizationTemplate(tempName, shape, iconShape, 
			      iconWidth, iconHeight, 
			      realization ? REALIZATION_EDGE : GENERALIZATION_EDGE, 
			      false, colorkey, buttonType);
  }

  protected void addGeneralizationTemplate(String tempName,
					   GraphEdgeBase shape, DrawShape iconShape,
					   int iconWidth, int iconHeight, 
					   int edgetype, 
					   boolean reverseEnds, 
					   String colorkey, 
					   int buttonType) {
    //System.out.println("UMLTemplate.addGeneralizationTemplate() reverseEnds=" + reverseEnds);

    if (shape == null) {
      shape = new LineShape(0, 20, 50, 20, true);
    }

    int lineStyle = (edgetype == REALIZATION_EDGE ? DrawAttr.DASHED_LINE : DrawAttr.SOLID_LINE);
    setLineAttr(shape, lineStyle, 
		ArrowAttr.ArrowType.HollowTriangle, 16, null, 0);
    if (colorkey != null) {
      setPenColor(shape, colorkey);
    }

    shape.setEdgeType(edgetype);

    UMLAssociation.AssociationType assocType = UMLAssociation.AssociationType.Generalization;
    if (edgetype == REALIZATION_EDGE) { 
      assocType = UMLAssociation.AssociationType.Realization;
    } else if (edgetype == MIXIN_EDGE) { 
      assocType = UMLAssociation.AssociationType.MixIn;
    }

    UMLAssociation model = new UMLAssociation(assocType);
    model.setNavigabilityToRight(null);
    model.setNavigabilityToLeft(null);
    shape.setModel(model);

    shape.setModelListener(new UMLGeneralizationModelListener(this));

    if (iconShape != null) { 
      setLineAttr(iconShape, lineStyle,
		  ArrowAttr.ArrowType.HollowTriangle, 16, null, 0);
      if (colorkey != null) {
	setPenColor(iconShape, colorkey);
      }

      add(new TemplateToolButton(tempName, shape, iconShape, iconWidth, iconHeight, false, true,
				 TemplateToolButton.DEFAULT_TOOL, reverseEnds, buttonType));
    } else { 
      add(new TemplateToolButton(tempName, shape, iconWidth, iconHeight, false, true,
				 TemplateToolButton.DEFAULT_TOOL, reverseEnds, buttonType));
    }
  }

  protected void addGeneralizationTemplate(String tempName, 
					   String protoName,
					   DrawShape iconShape,
					   int iconWidth, int iconHeight, 
					   boolean realization, 
					   boolean reverseEnds,
					   String colorkey, 
					   int buttonType) {
    if (iconShape != null) { 
      setLineAttr(iconShape,
		  realization ? DrawAttr.DASHED_LINE : DrawAttr.SOLID_LINE,
		  ArrowAttr.ArrowType.HollowTriangle, 16, null, 0);
      if (colorkey != null) {
	setPenColor(iconShape, colorkey);
      }
      
      add(new TemplateToolButton(tempName, protoName, iconShape, iconWidth, iconHeight, false, true,
				 TemplateToolButton.DEFAULT_TOOL, reverseEnds, buttonType));
    }      
  }

  protected void addGeneralizationShapeTemplate(String name, 
						GraphEdgeBase edge, 
						boolean realization, 
						String colorkey,
						int iconWidth, int iconHeight) { 
    //System.out.println("UMLTemplate.addGeneralizationShapeTemplate() name=" + name + " colorkey=" + colorkey); 
    if (name != null && 
	edge != null) { 
      setLineAttr(edge, 
		  realization ? DrawAttr.DASHED_LINE : DrawAttr.SOLID_LINE,
		  ArrowAttr.ArrowType.HollowTriangle, 16, null, 0);
      if (colorkey != null) {
	setPenColor(edge, colorkey);
      }
      addEdgeShapeTemplate(name, edge, iconWidth, iconHeight);
    }
  }

  protected void addAssociationTemplate(String tempName, 
					Navigability navRight,
					Navigability navLeft) {
    addAssociationTemplate(tempName, null, null, navRight, navLeft, null);
  }

  protected void addAssociationTemplate(String tempName, 
					Navigability navRight,
					Navigability navLeft, 
					String colorkey) {
    addAssociationTemplate(tempName, null, null, navRight, navLeft, colorkey);
  }

  protected void addAssociationTemplate(String tempName, 
					GraphEdgeBase shape,
					Navigability navRight, 
					Navigability navLeft) {
    addAssociationTemplate(tempName, shape, null, navRight, navLeft, null);
  }

  protected void addAssociationTemplate(String tempName, 
					GraphEdgeBase shape,
					Navigability navRight, 
					Navigability navLeft, 
					String colorkey) {
    addAssociationTemplate(tempName, shape, null, navRight, navLeft, colorkey);
  }

  protected void addAssociationTemplate(String tempName, 
					GraphEdgeBase shape, 
					DrawShape iconShape,
					Navigability navRight, 
					Navigability navLeft) {
    addAssociationTemplate(tempName, shape, iconShape, navRight, navLeft, null);
  }

  protected void addAssociationTemplate(String tempName, 
					GraphEdgeBase shape, 
					DrawShape iconShape,
					Navigability navRight, 
					Navigability navLeft, 
					String colorkey) {
    addAssociationTemplate(tempName, shape, iconShape, 36, 24, 
			   navRight, navLeft, colorkey,
			   TemplateToolButton.TOOL_PANEL_BUTTON);
  }

  protected void addAssociationTemplate(String tempName, 
					GraphEdgeBase shape, DrawShape iconShape,
					int iconWidth, int iconHeight, 
					Navigability navRight, Navigability navLeft, 
					String colorkey,
					int buttonType) {
    addAssociationTemplate(tempName, shape, iconShape, iconWidth, iconHeight, 
			   navRight, navLeft, false,			       
			   colorkey, buttonType);
  }

  protected void addAssociationTemplate(String tempName, 
					GraphEdgeBase shape, DrawShape iconShape,
					int iconWidth, int iconHeight, 
					Navigability navRight, Navigability navLeft, 
					boolean reverseEnds, 
					String colorkey,
					int buttonType) {
    if (shape == null) {
      shape = new GraphEdgeShape(0, 20, 50, 20);
      iconShape = new LineShape(0, 20, 50, 20);
    }
    setLineAttr(shape, DrawAttr.SOLID_LINE, getArrowType(navRight, null),
		arrowSize, getArrowType(navLeft, null), arrowSize);
    if (colorkey != null) {
      setPenColor(shape, colorkey);
    }

    shape.setEdgeType(ASSOCIATION_EDGE);

    UMLAssociation model = new UMLAssociation(UMLAssociation.AssociationType.Association);
    model.setNavigabilityToRight(navRight);
    model.setNavigabilityToLeft(navLeft);

    if (debug) {
      System.out.println(" UMLClassDiagramTemplate  UMLAssociation model: id=" + model.getId() + 
			 " navRight=" + model.getNavigabilityToRight() + 
			 "  navLeft=" + model.getNavigabilityToLeft());
    }

    shape.setModel(model);
    shape.setModelListener(new UMLAssociationModelListener(this));

    if (iconShape != null) { 
      setLineAttr(iconShape, DrawAttr.SOLID_LINE, getArrowType(navRight, null),
		  arrowSize, getArrowType(navLeft, null), arrowSize);
      if (colorkey != null) {
	setPenColor(iconShape, colorkey);
      }
      add(new TemplateToolButton(tempName, shape, iconShape, iconWidth, iconHeight, false, true,
				 TemplateToolButton.DEFAULT_TOOL, reverseEnds, buttonType));
    } else { 
      add(new TemplateToolButton(tempName, shape, iconWidth, iconHeight, false, true,
				 TemplateToolButton.DEFAULT_TOOL, reverseEnds, buttonType));
    }
  }

  protected void addAssociationTemplate(String tempName, 
					String protoName,
					DrawShape iconShape,
					int iconWidth, int iconHeight, 
					Navigability navRight, Navigability navLeft, 
					boolean reverseEnds, 
					String colorkey,
					int buttonType) {
    if (iconShape != null) { 
      setLineAttr(iconShape, DrawAttr.SOLID_LINE, getArrowType(navRight, null),
		  arrowSize, getArrowType(navLeft, null), arrowSize);
      if (colorkey != null) {
	setPenColor(iconShape, colorkey);
      }
      add(new TemplateToolButton(tempName, protoName, iconShape, 
				 iconWidth, iconHeight, false, true,
				 TemplateToolButton.DEFAULT_TOOL, 
				 reverseEnds, buttonType));
    }
  }

  public void addAssociationShapeTemplate(String name, 
					  GraphEdgeBase edge, 
					  String colorkey,
					  int iconWidth, int iconHeight) { 
    if (name != null && 
	edge != null) { 
      setLineAttr(edge, DrawAttr.SOLID_LINE, 
		  null, arrowSize, null, arrowSize);
      if (colorkey != null) {
	setPenColor(edge, colorkey);
      }
      addEdgeShapeTemplate(name, edge, iconWidth, iconHeight);
    }
  }

  protected static int arrowSize = 8;

  public OpenShape setNavigabilityArrows(OpenShape shape,
					 Navigability navRight, Navigability navLeft) {
    return setNavigabilityArrows(shape, navRight, null, navLeft, null);
  }

  public OpenShape setNavigabilityArrows(OpenShape shape,
					 Navigability navRight, 
					 UMLAssociationEnd.AggregationKind aggRight,
					 Navigability navLeft, 
					 UMLAssociationEnd.AggregationKind aggLeft) {
    if (shape != null) {
      setArrows(shape, getArrowType(navRight, aggRight), arrowSize,
	  getArrowType(navLeft, aggLeft), arrowSize);
    }
    return shape;
  }

  public OpenShape setRightNavigabilityArrow(OpenShape shape,
					     Navigability navRight) {
    return setRightNavigabilityArrow(shape, navRight, null);
  }

  public OpenShape setRightNavigabilityArrow(OpenShape shape,
					     Navigability navRight, 
					     UMLAssociationEnd.AggregationKind aggRight) {
    if (shape != null) {
      setHeadArrow(shape, getArrowType(navRight, aggRight), arrowSize);
    }
    return shape;
  }

  public OpenShape setLeftNavigabilityArrow(OpenShape shape,
					    Navigability navLeft) {
    return setLeftNavigabilityArrow(shape, navLeft, null);
  }

  public OpenShape setLeftNavigabilityArrow(OpenShape shape,
					    Navigability navLeft, 
					    UMLAssociationEnd.AggregationKind aggLeft) {
    if (shape != null) {
      setTailArrow(shape, getArrowType(navLeft, aggLeft), arrowSize);
    }
    return shape;
  }

  protected ArrowAttr.ArrowType getArrowType(Navigability nav,
					     UMLAssociationEnd.AggregationKind agg) {
    ArrowAttr.ArrowType arrow = ArrowAttr.ArrowType.NoArrow;
    if (agg != null) {
      switch (agg) {
      case None:
	if (nav != null) {
	  switch (nav) {
	  case Default:
	    arrow = ArrowAttr.ArrowType.NoArrow;
	    break;
	  case Navigable:
	    arrow = ArrowAttr.ArrowType.LineArrow;
	    break;
	  case NonNavigable:
	    arrow = ArrowAttr.ArrowType.XArrow;
	    break;
	  }
	} else {
	  arrow = ArrowAttr.ArrowType.NoArrow;
	}
	break;
      case Shared:
	if (nav != null) {
	  switch (nav) {
	  case Default:
	    arrow = ArrowAttr.ArrowType.HollowDiamond;
	    break;
	  case Navigable:
	    arrow = ArrowAttr.ArrowType.HollowDiamondArrow;
	    break;
	  case NonNavigable:
	    arrow = ArrowAttr.ArrowType.HollowDiamondX;
	    break;
	  }
	} else {
	  arrow = ArrowAttr.ArrowType.HollowDiamond;
	}
	break;
      case Composite:
	if (nav != null) {
	  switch (nav) {
	  case Default:
	    arrow = ArrowAttr.ArrowType.FilledDiamond;
	    break;
	  case Navigable:
	    arrow = ArrowAttr.ArrowType.FilledDiamondArrow;
	    break;
	  case NonNavigable:
	    arrow = ArrowAttr.ArrowType.FilledDiamondX;
	    break;
	  }
	} else {
	  arrow = ArrowAttr.ArrowType.FilledDiamond;
	}
	break;
      }
    } else {
      if (nav != null) {
	switch (nav) {
	case Default:
	  arrow = ArrowAttr.ArrowType.NoArrow;
	  break;
	case Navigable:
	  arrow = ArrowAttr.ArrowType.LineArrow;
	  break;
	case NonNavigable:
	  arrow = ArrowAttr.ArrowType.XArrow;
	  break;
	}
      } else {
	arrow = ArrowAttr.ArrowType.NoArrow;
      }
    }
    return arrow;
  }

  public boolean useIconInLabel() {
    return useIcon;
  }

  public void setUseIconInLabel(boolean b) {
    useIcon = b;
  }

  protected UMLTemplateStyle templateStyle = new UMLTemplateStyle();

  protected boolean useIcon = false;

  // notes style
  public static final String NOTES_BG = "template.UMLDiagram.Notes.bg";

  public static final String NOTES_FG = "template.UMLDiagram.Notes.fg";

  public static final String NOTES_FONT = "template.UMLDiagram.Notes.font";

  public static final String NOTES_COLOR = "template.UMLDiagram.Notes.color";

  public static final String STEREOTYPE_FONT = "template.UMLDiagram.Stereotype.font";

  public static final String STEREOTYPE_COLOR = "template.UMLDiagram.Stereotype.color";

  public static final String GENERICS_FONT = "template.UMLDiagram.Generics.font";

  public static final String GENERICS_COLOR = "template.UMLDiagram.Generics.color";

  public static final String PACKAGE_FONT = "template.UMLDiagram.PackageName.font";

  public static final String PACKAGE_COLOR = "template.UMLDiagram.PackageName.color";
  
  protected static final boolean debug = false;

}
